import json
import logging
from decimal import Decimal

from django.db import transaction
from django.utils import timezone

from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods
from users.models import Address
from xiaoyu_mall_new.utils.response_code import RETCODE
from xiaoyu_mall_new.utils.views import LoginRequiredJSONMixin

logger = logging.getLogger('django')


class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功页面"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        payment_method = request.GET.get('payment_method')
        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'payment_method': payment_method,
        }

        return render(request, 'order_success.html', context)


class OrderCommitView(LoginRequiredJSONMixin, View):
    """提交订单"""

    def post(self, request):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        if not all([address_id, pay_method]):
            return HttpResponseForbidden('缺少必要参数')

        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return HttpResponseForbidden('参数address_id错误')

        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return HttpResponseForbidden('参数pay_method错误')

        # 获取用户
        user = request.user
        # 拼接订单id
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

        # 显式开启一个事务
        with (transaction.atomic()):
            try:
                # 创建事务保存点
                save_id = transaction.savepoint()

                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND'],
                )

                # 从redis中读取购物车中被勾选的商品  {b'1':b'1',b'2:b'2'}
                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                # 从redis数据库中选出被勾选的商品sku_id  [b'1']
                selected = redis_conn.smembers('selected_%s' % user.id)

                carts = {}
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart.get(sku_id))

                # 通过sku模型类查询出在结算订单页面需要展示的商品sku
                sku_ids = carts.keys()
                # 遍历购物车中被勾选的商品
                for sku_id in sku_ids:

                    while True:  # ---------------
                        sku = SKU.objects.get(id=sku_id)
                        # 暂存原始库存销量
                        origin_stock = sku.stock  # ---------------
                        origin_sales = sku.sales  # ---------------

                        sku_count = carts[sku_id]
                        # 库存不足
                        if (sku_count > origin_stock):
                            # if (sku_count > sku.stock):
                            # 出错则回滚
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 库存与销量更新
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()

                        # 更新库存与销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales - sku_count
                        #
                        result = SKU.objects.filter(id=sku.id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if result == 0:
                            continue

                        # 修改spu销量
                        sku.spu.sales += sku_count
                        sku.spu.save()

                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )

                        order.total_count += sku_count
                        order.total_amount += sku.price * sku_count

                        break  # ------------------
                # 添加邮费
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
            # 显式一次性提交事务
            transaction.savepoint_commit(save_id)
        #         清除购物车中已结算商品
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *selected)
        pl.sadd('selected_%s' % user.id, *selected)

        pl.execute()

        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})


# Create your views here.
class OrderSettlementView(LoginRequiredMixin, View):
    """订单视图类"""

    def get(self, request):
        # 获取当前登录用户对象
        user = request.user
        # 查询当前登录用户是否有收货地址
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
            # 如果没有收货地址，那么就跳转到编辑收货地址页面
            if len(addresses) == 0:
                address_list = []
                context = {
                    'addresses': address_list
                }
                return render(request, 'user_center_site.html', context)
        except Exception as e:
            logger.error(e)
        # 从redis数据库中获取购物车数据  {b'1':b'1',b'2:b'2'}
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        # 从redis数据库中获取被勾选的商品sku_id  [b'1']
        redis_selected = redis_conn.smembers('selected_%s' % user.id)
        # 将被勾选的商品sku_id和数量组成一个新的数据
        new_cart_dict = {}
        for sku_id in redis_selected:
            new_cart_dict[int(sku_id)] = int(redis_cart[sku_id])
        # 通过sku模型类查询出在结算订单页面需要展示的商品sku
        sku_ids = new_cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)

        total_count = 0
        total_amount = Decimal(0.00)
        for sku in skus:
            # 遍历skus为每个sku补充count（数量）和amount（小计）
            sku.count = new_cart_dict[sku.id]
            sku.amount = sku.price * sku.count
            # # 累加数量和金额
            total_count += sku.count
            total_amount += sku.amount
        # 定义运费10元
        freight = Decimal(10.00)
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight
        }
        return render(request, 'place_order.html', context=context)
